/*
  Copyright (C), 2018-2020, ZhangYuanSheng
  FileName: PsiUtil
  Author:   ZhangYuanSheng
  Date:     2020/7/21 23:31
  Description:
  History:
  <author>          <time>          <version>          <desc>
  作者姓名            修改时间           版本号              描述
 */
package com.franklin.ideaplugin.api.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.franklin.ideaplugin.api.beans.GenericClass;
import com.franklin.ideaplugin.api.beans.GenericParameter;
import com.franklin.ideaplugin.easytesting.utils.PsiUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTypesUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author ZhangYuanSheng
 * @version 1.0
 */
public class PsiUtil {

    private PsiUtil() {
        // private
    }

    /**
     * 基础数据类型
     */
    private final static Set<String> BASIC_DATA_TYPES = Sets.newHashSet(
            String.class.getName(),
            Boolean.class.getName(),
            Byte.class.getName(),
            Character.class.getName(),
            Double.class.getName(),
            BigDecimal.class.getName(),
            Float.class.getName(),
            Integer.class.getName(),
            Long.class.getName(),
            Short.class.getName(),
            Void.class.getName(),
            "boolean",
            "byte",
            "char",
            "double",
            "float",
            "int",
            "long",
            "short",
            "void"
    );

    /**
     * 获取psi元素的注释
     * @param psiJavaDocumentedElement
     * @return
     */
    public static String getDocumentOfPsiElement(@NotNull PsiJavaDocumentedElement psiJavaDocumentedElement){
        return Optional.ofNullable(psiJavaDocumentedElement.getDocComment())
                .map(PsiElement::getText)
                .orElse("");
    }

    /**
     * 判断是否是main方法
     * @param psiMethod
     * @return
     */
    public static boolean isMainMethod(@NotNull PsiMethod psiMethod){
        if (!psiMethod.getName().equals("main")){
            return false;
        }
        List<PsiParameter> psiParameterList = PsiUtils.getPsiMethodParameters(psiMethod);
        if (psiParameterList.size() != 1){
            return false;
        }
        String canonicalText = psiParameterList.get(0).getType().getCanonicalText();
        return canonicalText.startsWith("java.lang.String")
                && (canonicalText.endsWith("[]") || canonicalText.endsWith("..."))
                && getArrayDimension(canonicalText) == 1;

    }

    /**
     * 获取数组的维数
     * @param classQualifiedName
     * @return
     */
    public static int getArrayDimension(String classQualifiedName){
        if (!isArrayClass(classQualifiedName)){
            throw new IllegalArgumentException(classQualifiedName + " is not a array class");
        }
        if (classQualifiedName.contains("...")){
            classQualifiedName = classQualifiedName.replace("...","[]");
        }
        int count = 0;
        String tempName = classQualifiedName;
        while (tempName.contains("[]")){
            count++;
            tempName = tempName.replaceFirst("\\[]","");
        }
        return count;
    }

    /**
     * 解析参数依赖的所有类
     * @param psiType
     * @return
     */
    public static List<String> resolveDependencyClassOfPsiType(@NotNull PsiType psiType){
        String fullClassNameText = psiType.getCanonicalText();
        //将泛型标识替换为空格，方便切割
        //如com.franklin.springbootdemo.vo.ResponseVo<java.util.List<com.franklin.springbootdemo.entity.DemoData>>
        String classNameStrList = fullClassNameText.replaceAll("<", " ")
                .replaceAll(">", " ")
                .replaceAll(",", " ");
        return Arrays.stream(classNameStrList.split(" "))
                .filter(StrUtil::isNotBlank)
                .filter(name -> !PsiUtil.isBasicDataTypes(name))
                .distinct()
                .collect(Collectors.toList());
    }

    /**
     * 解析泛型信息
     * @param project
     * @param psiType
     * @return
     */
    public static GenericClass resolveGenericClass(@NotNull Project project, @NotNull PsiType psiType){
        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
        GlobalSearchScope globalSearchScope = GlobalSearchScope.allScope(project);
        String fullClassNameText = psiType.getCanonicalText();

        //用栈匹配泛型
        Deque<String> deque = new ArrayDeque<>();
        StringBuilder classNameBuilder = new StringBuilder();
        //缓存结果
        Map<String, GenericClass> codeResultMap = Maps.newHashMap();
        Map<Integer, String> hashCodeMap = Maps.newHashMap();
        for (int i = 0; i < fullClassNameText.length(); i++) {
            char c = fullClassNameText.charAt(i);
            if (c != '<' && c != '>' && c != ',') {
                //类名
                classNameBuilder.append(c);
            } else if (c == '<' || c == ',') {
                //类名结束
                deque.addFirst(classNameBuilder.toString());
                classNameBuilder = new StringBuilder();
                deque.addFirst(String.valueOf(c));
            } else {
                //泛型结束
                String tempStr = null;
                //泛型列表（正序）
                List<String> genericParameterClassNameList = Lists.newArrayList(classNameBuilder.toString());
                while (!(tempStr = deque.removeFirst()).equals("<")) {
                    if (!tempStr.equals(",")) {
                        genericParameterClassNameList.add(0, tempStr);
                    }
                }

                String className = deque.removeFirst();
                PsiClass psiClass = javaPsiFacade.findClass(className, globalSearchScope);
                if (Objects.isNull(psiClass)) {
                    throw new RuntimeException();
                }
                //泛型列表
                PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
                List<GenericParameter> genericParameterList = Lists.newArrayList();
                for (int j = 0; j < typeParameters.length; j++) {
                    String name = genericParameterClassNameList.get(j);
                    GenericClass genericClass = null;
                    if (NumberUtil.isNumber(name)) {
                        name = hashCodeMap.getOrDefault(NumberUtil.parseInt(name), name);
                        genericClass = codeResultMap.get(name);
                    }
                    if (Objects.isNull(genericClass)) {
                        PsiClass genericPsiClass = javaPsiFacade.findClass(name, globalSearchScope);
                        if (Objects.nonNull(genericPsiClass)) {
                            genericClass = new GenericClass(genericPsiClass, Collections.emptyList());
                        }
                    }
                    PsiTypeParameter typeParameter = typeParameters[j];
                    GenericParameter genericParameter = new GenericParameter(typeParameter, typeParameter.getName(), name, genericClass);
                    genericParameterList.add(genericParameter);
                }
                GenericClass genericClass = new GenericClass(psiClass, genericParameterList);
                String genericParameterClassName = genericParameterClassNameList.stream()
                        .map(genericClassName -> {
                            if (NumberUtil.isNumber(genericClassName)) {
                                genericClassName = hashCodeMap.getOrDefault(NumberUtil.parseInt(genericClassName), genericClassName);
                            }
                            return genericClassName;
                        })
                        .collect(Collectors.joining(","));

                String key = className + "<" + genericParameterClassName + ">";
                codeResultMap.put(key, genericClass);
                int hashCode = key.hashCode();
                hashCodeMap.put(hashCode, key);
                classNameBuilder = new StringBuilder().append(hashCode);
            }
        }

        //获取结果
        return codeResultMap.get(fullClassNameText);
    }

    /**
     * 生成泛型对象默认数据
     * @param genericClass
     * @return
     */
    public static Object getDefaultDataOfGenericClass(GenericClass genericClass) {
        if (Objects.isNull(genericClass)) {
            return Collections.emptyMap();
        }
        PsiClass psiClass = genericClass.getPsiClass();
        if (Objects.isNull(psiClass)){
            return null;
        }

        if (isBasicDataTypes(psiClass.getQualifiedName())){
            //基本数据类型
            return getDefaultData(psiClass.getName());
        }

        Project project = psiClass.getProject();
        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
        GlobalSearchScope globalSearchScope = GlobalSearchScope.allScope(project);
        Map<String, Object> fieldMap = Maps.newLinkedHashMap();
        List<PsiUtil.FieldMethod> fieldMethodList = PsiUtil.getFieldsMethod(psiClass);

        //泛型
        List<GenericParameter> genericParameterList = genericClass.getGenericParameterList();
        Map<String, GenericParameter> genericKeyNameParamMap = genericParameterList.stream()
                .collect(Collectors.toMap(GenericParameter::getName, Function.identity()));

        if (CollectionUtil.isNotEmpty(genericKeyNameParamMap)) {
            //泛型
            PsiClass collectionPsiClass = javaPsiFacade.findClass("java.util.Collection", globalSearchScope);
            PsiClass mapPsiClass = javaPsiFacade.findClass("java.util.Map", globalSearchScope);
            if (psiClass.isInheritor(collectionPsiClass, true) || psiClass.equals(collectionPsiClass)) {
                //集合
                List<GenericParameter> collectionClassGenericParameterList = genericClass.getGenericParameterList();
                for (GenericParameter collectionGenericParameter : collectionClassGenericParameterList) {
                    return Collections.singletonList(getDefaultDataOfGenericClass(collectionGenericParameter.getGenericClass()));
                }
            } else if (psiClass.isInheritor(mapPsiClass, true) || psiClass.equals(mapPsiClass)) {
                //Map
                Map<Object, Object> map = Maps.newLinkedHashMap();
                GenericParameter k = genericKeyNameParamMap.get("K");
                GenericParameter v = genericKeyNameParamMap.get("V");
                Object kDefaultValue = PsiUtil.getDefaultData(k.getGenericClass().getPsiClass());
                Object vDefaultValue = PsiUtil.getDefaultData(v.getGenericClass().getPsiClass());
                Object kValue = kDefaultValue;
                Object vValue = vDefaultValue;
                if (kDefaultValue instanceof Collection || kDefaultValue instanceof Map) {
                    kValue = getDefaultDataOfGenericClass(k.getGenericClass());
                }
                if (vDefaultValue instanceof Collection || vDefaultValue instanceof Map) {
                    vValue = getDefaultDataOfGenericClass(v.getGenericClass());
                }
                map.put(kValue, vValue);
                return map;
            }
        }

        for (PsiUtil.FieldMethod fieldMethod : fieldMethodList) {
            PsiField psiField = fieldMethod.getField();
            if (psiField == null) {
                // 如果该 Getter|Setter 方法所对应的Field为空，则跳过
                continue;
            }

            PsiType psiType = psiField.getType();
            String typeName = psiType.getCanonicalText();
            if (typeName.equals(psiClass.getQualifiedName())) {
                //同类名跳过
                fieldMap.put(fieldMethod.getFieldName(), null);
                continue;
            }
            if (CollectionUtil.isNotEmpty(genericKeyNameParamMap)) {
                GenericParameter genericParameter = genericKeyNameParamMap.get(typeName);
                if (Objects.nonNull(genericParameter)) {
                    fieldMap.put(
                            fieldMethod.getFieldName(),
                            getDefaultDataOfGenericClass(genericParameter.getGenericClass())
                    );
                }else {
                    fieldMap.put(
                            fieldMethod.getFieldName(),
                            PsiUtil.getDefaultValueOfPsiType(psiType)
                    );
                }
            } else {
                fieldMap.put(
                        fieldMethod.getFieldName(),
                        PsiUtil.getDefaultValueOfPsiType(psiType)
                );
            }

        }
        return fieldMap;
    }

    /**
     * 获取所有的PsiClass
     */
    @NotNull
    public static List<PsiClass> getAllPsiClass(@NotNull PsiClass psiClass) {
        if (psiClass.isAnnotationType()) {
            return Collections.emptyList();
        }
        List<PsiClass> list = new ArrayList<>();
        list.add(psiClass);
        list.addAll(
                Stream.of(PsiClassImplUtil.getAllInnerClasses(psiClass))
                        // 忽略注解
                        .filter(item -> !item.isAnnotationType())
                        .collect(Collectors.toList())
        );
        return list;
    }

    /**
     * 获取所有的PsiClass
     */
    @NotNull
    public static List<PsiClass> getAllPsiClass(@NotNull PsiFile psiFile) {
        PsiElement[] elements = psiFile.getChildren();
        if (elements.length < 1) {
            return Collections.emptyList();
        }

        return Stream.of(elements)
                .filter(PsiClass.class::isInstance)
                .map(PsiClass.class::cast)
                .map(PsiUtil::getAllPsiClass)
                .flatMap(Collection::stream)
                // 忽略注解
                .filter(item -> !item.isAnnotationType())
                .collect(Collectors.toList());
    }

    /**
     * 获取PsiParameter的PsiClass
     *
     * @param psiParameter 参数
     * @return PsiClass
     */
    @Nullable
    public static PsiClass getClassOfPsiParameter(@Nullable PsiParameter psiParameter) {
        if (psiParameter == null) {
            return null;
        }
        PsiTypeElement psiTypeElement = psiParameter.getTypeElement();
        if (psiTypeElement == null) {
            return null;
        }
        PsiJavaCodeReferenceElement referenceElement = psiTypeElement.getInnermostComponentReferenceElement();
        if (referenceElement == null) {
            return null;
        }
        PsiElement psiElement = referenceElement.resolve();
        if (!(psiElement instanceof PsiClass)) {
            return null;
        }
        return (PsiClass) psiElement;
    }

    /**
     * 获取PsiMethod的参数列表
     *
     * @param psiMethod 方法
     * @return PsiParameter
     */
    @NotNull
    public static List<PsiParameter> getParametersOfPsiMethod(@NotNull PsiMethod psiMethod) {
        PsiParameterList parameterList = psiMethod.getParameterList();
        if (parameterList.isEmpty()) {
            return Collections.emptyList();
        }
        return Arrays.asList(parameterList.getParameters());
    }

    /**
     * 是否继承
     * @param parent
     * @param child
     * @return
     */
    public static boolean isInheritorOrEquals(PsiClass parent,PsiClass child){
        if (Objects.isNull(parent) || Objects.isNull(child)){
            return false;
        }
        return child.isInheritor(parent,true) || parent.equals(child);
    }

    /**
     * 是否是可变形参
     * @param psiType
     * @return
     */
    public static boolean isArrayType(PsiType psiType){
        return isArrayClass(psiType.getCanonicalText());
    }

    /**
     * 是否是数组
     * @param classQualifiedName
     * @return
     */
    public static boolean isArrayClass(String classQualifiedName){
        return classQualifiedName.endsWith("[]") || classQualifiedName.endsWith("...");
    }

    /**
     * 获取可变形参的真正类型
     * @param psiType
     * @return
     */
    public static PsiType getVarAgsTrueType(PsiType psiType){
        if (!isArrayType(psiType)){
            return psiType;
        }
        String canonicalText = psiType.getCanonicalText();
        canonicalText = canonicalText.substring(0,canonicalText.length() - "...".length());
        Project currProject = ProjectUtils.getCurrProject();
        return PsiType.getTypeByName(canonicalText, currProject,GlobalSearchScope.allScope(currProject));
    }

    /**
     * 获取PsiType的默认值
     *
     * @return [BasicDataType] | Map | List
     */
    @Nullable
    public static Object getDefaultValueOfPsiType(@NotNull PsiType psiType) {
        String canonicalText = psiType.getCanonicalText();

        // 基本类型  boolean
        if (PsiType.BOOLEAN.equals(psiType) || "java.lang.Boolean".equals(canonicalText)) {
            return false;
        }

        // 基本类型  String
        Project currProject = ProjectUtils.getCurrProject();

        PsiClass classType = PsiTypesUtil.getPsiClass(psiType);
        PsiClass charSequenceClass = JavaPsiFacade.getInstance(currProject)
                .findClass("java.lang.CharSequence", GlobalSearchScope.allScope(currProject));
        if (isInheritorOrEquals(charSequenceClass,classType)){
            return "String";
        }
        if (canonicalText.endsWith("java.lang.String")) {
            return "String";
        }

        if (PsiType.LONG.equals(psiType) || "java.lang.Long".equals(canonicalText)) {
            return 0L;
        }

        if (PsiType.DOUBLE.equals(psiType) || "java.lang.Double".equals(canonicalText)) {
            return 0D;
        }

        if (PsiType.FLOAT.equals(psiType) || "java.lang.Float".equals(canonicalText)) {
            return 0F;
        }

        if (BigDecimal.class.getName().equals(canonicalText)) {
            return 0F;
        }

        // 基本类型|数字
        if (PsiType.INT.equals(psiType) || "java.lang.Integer".equals(canonicalText)
                || PsiType.BYTE.equals(psiType) || "java.lang.Byte".equals(canonicalText)
                || PsiType.SHORT.equals(psiType) || "java.lang.Short".equals(canonicalText)
                || "java.math.BigInteger".equals(canonicalText)
                || "java.math.BigDecimal".equals(canonicalText)) {
            return 0;
        }

        // 原生的数组
        if (isArrayType(psiType)) {
            return Collections.emptyList();
        }

        if (psiType instanceof PsiClassReferenceType) {
            // Object | String | Integer | List<?> | Map<K, V>
            PsiClassReferenceType type = (PsiClassReferenceType) psiType;
            // 通过 Getter|Setter 读取
            PsiClass psiClass = type.resolve();
            if (psiClass == null) {
                return null;
            }

            GenericClass genericClass = resolveGenericClass(psiClass.getProject(), psiType);
            if (Objects.nonNull(genericClass)){
                return getDefaultDataOfGenericClass(genericClass);
            }
            final Object hasResult = getDefaultData(psiClass);
            if (hasResult != null) {
                return hasResult;
            }

            return getDefaultDataOfObject(psiClass);
        }

        // 常见的List 和Map
        if (canonicalText.startsWith("java.util.")) {
            if (canonicalText.contains("Map")) {
                return Collections.emptyMap();
            }
            if (canonicalText.contains("List")) {
                return Collections.emptyList();
            }
        }

        return null;
    }

    /**
     * 生成对象默认值
     * @param psiClass
     * @return
     */
    public static Map<String,Object> getDefaultDataOfObject(@NotNull PsiClass psiClass){
        Map<String, Object> fieldMap = Maps.newLinkedHashMap();
        List<PsiUtil.FieldMethod> fieldMethodList = PsiUtil.getFieldsMethod(psiClass);
        for (PsiUtil.FieldMethod fieldMethod : fieldMethodList) {
            PsiField psiField = fieldMethod.getField();
            if (psiField == null) {
                // 如果该 Getter|Setter 方法所对应的Field为空，则跳过
                continue;
            }

            String canonicalText = psiField.getType().getCanonicalText();
            if (canonicalText.equals(psiClass.getQualifiedName())){
                //同类名跳过
                fieldMap.put(fieldMethod.getFieldName(), null);
                continue;
            }

            fieldMap.put(
                    fieldMethod.getFieldName(),
                    PsiUtil.getDefaultValueOfPsiType(psiField.getType())
            );
        }
        return fieldMap;
    }

    /**
     * 获取PsiClass的默认值
     *
     * @param psiClass class
     * @return "NULL" | List | Set | Map
     */
    @Nullable
    public static Object getDefaultData(@Nullable PsiClass psiClass) {
        if (psiClass == null) {
            return null;
        }
        String qualifiedName = psiClass.getQualifiedName();
        if (qualifiedName == null) {
            return null;
        }
        // 基本类型  String
        Project project = psiClass.getProject();
        PsiClass collectionClass = JavaPsiFacade.getInstance(project)
                .findClass("java.util.Collection", GlobalSearchScope.allScope(project));
        PsiClass mapClass = JavaPsiFacade.getInstance(project)
                .findClass("java.util.Map", GlobalSearchScope.allScope(project));
        if (isInheritorOrEquals(mapClass,psiClass)){
            return Collections.emptyMap();
        }
        if (isInheritorOrEquals(collectionClass,psiClass)){
            return Collections.emptyList();
        }
        if (qualifiedName.equals(List.class.getName())) {
            return Collections.emptyList();
        }
        if (qualifiedName.equals(Set.class.getName())) {
            return Collections.emptySet();
        }
        if (qualifiedName.equals(Map.class.getName())) {
            return Collections.emptyMap();
        }
        if (qualifiedName.equals(Date.class.getName())) {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());
        }
        if (qualifiedName.equals("com.alibaba.fastjson.JSONArray") || qualifiedName.equals("com.alibaba.fastjson2.JSONArray")){
            return Collections.emptyList();
        }

        final String libPackage = "java.util(.concurrent)?.[a-zA-Z0-9]*";
        @Language("RegExp") final String regList = libPackage + "List";
        @Language("RegExp") final String regSet = libPackage + "Set";
        @Language("RegExp") final String regMap = libPackage + "Map";
        if (Pattern.compile(regList).matcher(qualifiedName).find()) {
            return Collections.emptyList();
        }
        if (Pattern.compile(regSet).matcher(qualifiedName).find()) {
            return Collections.emptySet();
        }
        if (Pattern.compile(regMap).matcher(qualifiedName).find()) {
            return Collections.emptyMap();
        }

        if (Pattern.compile(libPackage).matcher(qualifiedName).find()) {
            return "NULL";
        }

        if (psiClass.getName() != null) {
            Object defaultData = getDefaultData(psiClass.getName());
            if (Objects.isNull(defaultData)){
                return getDefaultDataOfObject(psiClass);
            }
            return defaultData;
        }

        return null;
    }

    @Nullable
    public static Object getDefaultData(@NotNull String classType) {
        Object data = null;
        switch (classType.toLowerCase(Locale.ROOT)) {
            case "string":
                data = "demoData";
                break;
            case "char":
            case "character":
                data = 'A';
                break;
            case "byte":
            case "short":
            case "int":
            case "integer":
            case "long":
                data = 0;
                break;
            case "float":
            case "double":
            case "bigdecimal":
                data = 0.0;
                break;
            case "boolean":
                data = true;
                break;
            default:
                break;
        }
        return data;
    }

    /**
     * (有序) 获取 PsiClass 中定义的 Getter|Setter 方法，及对应的 Field（可能为空）
     *
     * @param psiClass Class
     * @return FieldsMethods
     * @see PsiUtil.FieldMethod
     */
    @NotNull
    public static List<FieldMethod> getFieldsMethod(@NotNull PsiClass psiClass) {
        LinkedHashMap<String, FieldMethod> map = new LinkedHashMap<>();

        // 读取字段
        for (PsiField field : psiClass.getAllFields()) {
            if (hasStaticModifier(field.getModifierList()) || hasFinalModifier(field.getModifierList())) {
                // 如果字段是static或final则跳过
                continue;
            }
            map.put(field.getName(), new FieldMethod(field.getName(), field));
        }

        // 读取Getter|Setter方法对应的字段
        for (PsiMethod method : psiClass.getAllMethods()) {
            final String prefixGet = "get";
            final String prefixSet = "Set";
            final String name = method.getName();

            if (name.length() < 4 || !(name.startsWith(prefixGet) || name.startsWith(prefixSet))) {
                // 如果不是Getter|Setter方法则直接跳过
                continue;
            }

            if (!hasPublicModifier(psiClass.getModifierList()) || hasStaticModifier(psiClass.getModifierList())) {
                // 如果方法修饰符不是public或者方法是静态的则直接跳过
                continue;
            }

            // 截取方法标示的字段名
            final String fieldName = name.substring(3, 4).toLowerCase() + name.substring(4);
            final FieldMethod fieldMethod;
            if (map.containsKey(fieldName)) {
                fieldMethod = map.get(fieldName);
                if (fieldMethod.getField() != null && hasPublicModifier(fieldMethod.getField().getModifierList())) {
                    // 如果字段Field不为空切是public修饰则跳过检查Getter|Setter
                    continue;
                }
            } else {
                PsiField field = psiClass.findFieldByName(fieldName, true);
                if (field == null
                        // 如果是static属性
                        || hasStaticModifier(field.getModifierList())
                        // 如果是final属性
                        || hasFinalModifier(field.getModifierList())) {
                    continue;
                }
                fieldMethod = new FieldMethod(fieldName, field);
                map.put(fieldName, fieldMethod);
            }

            if (name.startsWith(prefixGet)) {
                fieldMethod.addFieldGetter(method);
            } else {
                fieldMethod.addFieldSetter(method);
            }
        }

        return new ArrayList<>(map.values());
    }

    /**
     * 是否是基本数据类型
     *
     * @param type java.lang.String | java.lang.Integer | char | int
     * @return boolean
     */
    public static boolean isBasicDataTypes(String type) {
        if (type == null) {
            return false;
        }
        return BASIC_DATA_TYPES.contains(type);
    }

    /**
     * 是否是Kotlin中的基本数据类型
     *
     * @param type java.lang.String | java.lang.Integer | char | int
     * @return boolean
     */
    public static boolean isKotlinBasicDataTypes(String type) {
        if (type == null) {
            return false;
        }
        final String[] classes = new String[]{
                "Boolean",
                "Byte",
                "Int",
                "Short",
                "Long",
                "Float",
                "Double",
                "Char",
                "Number",
                "Array",
                "String"
        };
        for (String clazz : classes) {
            if (clazz.equals(type)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否是公共(public)方法
     *
     * @param target PsiModifierList的实现类
     * @return bool
     * @see PsiUtil#hasModifier(PsiModifierList, String)
     */
    public static boolean hasPublicModifier(@Nullable PsiModifierList target) {
        return PsiUtil.hasModifier(target, PsiModifier.PUBLIC);
    }

    /**
     * 是否是私有(private)方法
     *
     * @param target PsiModifierList的实现类
     * @return bool
     * @see PsiUtil#hasModifier(PsiModifierList, String)
     */
    public static boolean hasPrivateModifier(@Nullable PsiModifierList target) {
        return PsiUtil.hasModifier(target, PsiModifier.PRIVATE);
    }

    /**
     * 是否是静态(static)方法
     *
     * @param target PsiModifierList的实现类
     * @return bool
     * @see PsiUtil#hasModifier(PsiModifierList, String)
     */
    public static boolean hasStaticModifier(@Nullable PsiModifierList target) {
        return PsiUtil.hasModifier(target, PsiModifier.STATIC);
    }

    /**
     * 是否是最终(final)方法
     *
     * @param target PsiModifierList的实现类
     * @return bool
     * @see PsiUtil#hasModifier(PsiModifierList, String)
     */
    public static boolean hasFinalModifier(@Nullable PsiModifierList target) {
        return PsiUtil.hasModifier(target, PsiModifier.FINAL);
    }

    /**
     * 是否具有指定修饰符
     *
     * @param target PsiModifierList的实现类
     * @return bool
     */
    public static boolean hasModifier(@Nullable PsiModifierList target, @PsiModifier.ModifierConstant @NotNull String modifier) {
        if (target == null) {
            return false;
        }
        // 是否具有修饰符属性
        return target.hasModifierProperty(modifier);
    }

    public static class FieldMethod {

        /**
         * Getter方法, 可能有多个
         */
        private final List<PsiMethod> fieldGetters;
        /**
         * Setter方法, 可能有多个
         */
        private final List<PsiMethod> fieldSetters;
        private String fieldName;
        private PsiField field;

        /**
         * Getter的无参方法
         */
        private PsiMethod noParameterMethodOfGetter;

        private FieldMethod() {
            fieldGetters = new ArrayList<>();
            fieldSetters = new ArrayList<>();
        }

        public FieldMethod(@NotNull String fieldName) {
            this(fieldName, null);
        }

        public FieldMethod(@NotNull String fieldName, @Nullable PsiField field) {
            this();
            this.fieldName = fieldName;
            this.field = field;
        }

        @NotNull
        public String getFieldName() {
            return fieldName;
        }

        public void setFieldName(@NotNull String fieldName) {
            this.fieldName = fieldName;
        }

        @Nullable
        public PsiField getField() {
            return field;
        }

        public void setField(@Nullable PsiField field) {
            this.field = field;
        }

        @NotNull
        public List<PsiMethod> getFieldGetters() {
            return fieldGetters;
        }

        public void addFieldGetter(@NotNull PsiMethod fieldGetter) {
            this.fieldGetters.add(fieldGetter);
            if (fieldGetter.getParameterList().isEmpty()) {
                this.setNoParameterMethodOfGetter(fieldGetter);
            }
        }

        @NotNull
        public List<PsiMethod> getFieldSetters() {
            return fieldSetters;
        }

        public void addFieldSetter(@NotNull PsiMethod fieldSetter) {
            this.fieldSetters.add(fieldSetter);
        }

        public boolean emptyGetter() {
            return getFieldGetters().isEmpty();
        }

        public boolean emptySetter() {
            return getFieldSetters().isEmpty();
        }

        @Nullable
        public PsiMethod getNoParameterMethodOfGetter() {
            return noParameterMethodOfGetter;
        }

        public void setNoParameterMethodOfGetter(@NotNull PsiMethod noParameterMethod) {
            this.noParameterMethodOfGetter = noParameterMethod;
        }
    }
}
